package net.edwardstx.hibernateutils;

import java.io.Serializable;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class HibernateDAO implements HibernateDAOInterface{
//	private Logger logger = Logger.getLogger(this.getClass().getName());
	private Logger logger = LoggerFactory.getLogger(this.getClass().getName());
	private SessionFactory sessionFactory;
	private ThreadLocal<Session> localSession = new ThreadLocal<Session>(){
		@Override
		protected Session  initialValue() {
			return null;
		}
	};
	private ThreadLocal<Transaction> localTransaction = new ThreadLocal<Transaction>(){
		@Override
		protected Transaction  initialValue() {
			return null;
		}
	};
	
//	public static interface HibernateTransaction extends Transaction{
//		
//	}
//	private Session session = null;
	public static class Parameter{
		private Object objectValue;
		private String stringName;
		@Deprecated
		public Parameter(Object objectValueNew, String stringNameNew){
			this.setValue(objectValueNew);
			this.setName(stringNameNew);
		}
		public Object getValue() {
			return objectValue;
		}
		public void setValue(Object objectValue) {
			this.objectValue = objectValue;
		}
		public String getName() {
			return stringName;
		}
		public void setName(String stringName) {
			this.stringName = stringName;
		}
		
		
	}
	
	public class Parameters extends ArrayList<Parameter>{
		private static final long	serialVersionUID	= 8816271571422562746L;
		private String				stringSelectFrom	= null;
		private String				stringWhere			= null;
		private String				stringOrderBy		= null;
		private Integer				intCount			= null;
        private Integer				intOffset			= null;

		
		private LockMode			lockMode			= null;
		
		public Parameters(){
			super();
		}
		public Parameters(List<Parameter> p){
			super(p);
		}
		public Parameters(int intSize){
			super(intSize);
		}
		public String getSelectFrom() {
			return stringSelectFrom;
		}
		public void setSelectFrom(String stringSelectFromNew) {
			this.stringSelectFrom = stringSelectFromNew;
		}
		public String getWhere() {
			return stringWhere;
		}
		public void setWhere(String stringWhereNew) {
			this.stringWhere = stringWhereNew;
		}
		public String getOrderBy() {
			return stringOrderBy;
		}
		public void setOrderBy(String stringOrderByNew) {
			this.stringOrderBy = stringOrderByNew;
		}
		public void addParameter(String stringName, Serializable value){
			this.add(new Parameter(value, stringName));
		}
		public void setLockMode(LockMode lockMode) {
			this.lockMode = lockMode;
		}
		public LockMode getLockMode() {
			return lockMode;
		}
		public Integer getCount() {
			return intCount;
		}
		public void setCount(Integer intCount) {
			this.intCount = intCount;
		}
		public Integer getOffset() {
			return intOffset;
		}
		public void setOffset(Integer intOffset) {
			this.intOffset = intOffset;
		}

		

		
		
	}
	
	public static final String convertFieldToParamater(String stringFeild){
		return "_" + stringFeild.replace('.','_');
	}
	
	public static final String dtoAlias(Class<? extends HibernateDTO> classDTO){
		return dtoAlias(classDTO,null);
	}
	public static final String dtoAlias(Class<? extends HibernateDTO> classDTO, String stringFeild){
		String stringReturn = " " + classDTO.getSimpleName().toLowerCase();
		if(stringFeild != null)
			stringReturn = stringReturn + "." + stringFeild + " ";
		return stringReturn;
	}
	public static final String fromDTO(Class<? extends HibernateDTO> classDTO){
		return " " + classDTO.getName() + " as " + dtoAlias(classDTO,null) + " ";
	}
	protected HibernateDAO(HibernateDAOFactory hibernateDAOFactory){
		this.sessionFactory = hibernateDAOFactory.getEntityManagerFactory();
	}
	
	protected void preStartSession(){
		
	}
	
	protected Session postStartSession(Session session){
		return session;
	}
	
	protected final Session getSession() throws HibernateException {
		getLogger().trace("Get Session Request");
//		return sessionFactory.getCurrentSession();
		synchronized(sessionFactory){
			if(localSession.get() == null)
			{
				getLogger().trace("Opening New Session");
				preStartSession();
				localSession.set(postStartSession(sessionFactory.openSession()));
//				localSession.get().setFlushMode(FlushMode.COMMIT);
			}
		}
		return localSession.get();
	}
	
	protected final Transaction getTransaction() throws HibernateException {
		getLogger().trace("Get Transaction");
		if(localTransaction.get() != null){
			getLogger().trace("Using current transaction");
			return localTransaction.get();
		}
		getLogger().trace("Starting new transaction");
		return getSession().beginTransaction();
	}
	
	@Override
	public void endTransaction(){
		getLogger().trace("End Transaction");
		Transaction t = localTransaction.get();
		if(t != null){
			try{
				t.commit();
			}catch(Exception exception){
				try{
					t.rollback();
				} catch(Exception exceptionRollBack){
					getLogger().error( "Unable to rollback transaction", exceptionRollBack);
					closeSession();
				}
			}finally{
				localTransaction.set(null);
			}
		}
		
	}
	@Override
	public Transaction beginTransaction(){
		getLogger().trace("Begin Transaction");
		localTransaction.set(getSession().beginTransaction());
		return localTransaction.get();
	}
	
	
	protected final void returnTransaction(Transaction transaction){
		getLogger().trace("Return Transaction");
		if(localTransaction.get() == null){
			getLogger().debug("Temperarry  Transaction, commiting");
			transaction.commit();
		}
	}
	protected final void rollbackTransaction(Transaction transaction){
		getLogger().debug("Rolling back Transaction");
		if(transaction == null){
			getLogger().debug("NO transaction");
			return;
		}
			
		try{
			transaction.rollback();
		} catch(Exception exceptionRollBack){
			getLogger().error( "Unable to rollback transaction", exceptionRollBack);
			closeSession();
		}finally{
			getLogger().trace("Setting Transaction to null");
			localTransaction.set(null);
		}
	}
	
	
//	public Transaction persist (Object proxy){
//		Session sessionTemp = null;
//		Transaction transaction = null;
//		try{
//			sessionTemp = getSession();
//			transaction = sessionTemp.beginTransaction();
//			sessionTemp.persist(proxy);
//		}catch(Exception exception){
//		
//		}
//		return transaction;
//	}
//	public <T extends HibernateDTO> T initilize(T proxy){
//		if(!Hibernate.isInitialized(proxy)){
//			Session sessionTemp = null;
//			Transaction transaction = null;
//			try{
//				sessionTemp = getSession();
//				transaction = sessionTemp.beginTransaction();
//				sessionTemp.persist(proxy);
//				Hibernate.initialize(proxy);
//				getSession().getTransaction().commit();
//			} catch(Exception exception){
//				getLogger().warn( "Unable to initilize " + proxy.getClass().getName(), exception);
//				transaction.rollback();
//				try{
//					transaction.rollback();
//				} catch(Exception exceptionRollBack){
//					getLogger().error( "Unable to rollback transaction", exceptionRollBack);
//					sessionTemp.close();
//				}
//				
////				closeSession();
//		} finally{
//				returnEntityManager(sessionTemp);
//		}
//		}
//		return proxy;
//		
//	}
	protected void preEndSession(Session session){
	}
	
	protected void postEndSession(){
		
	}
	@Override
	public final synchronized void closeSession(){
		getLogger().trace("Close Session Request");
		if(localSession.get() != null){
			getLogger().trace("Closing Session");
			try {
				preEndSession(localSession.get());
			} catch (Throwable throwable) {
				getLogger().error("Error executing preEndSession hooks", throwable);
			}
			try {
				localSession.get().close();
			} finally {
				localSession.set(null);
			}
			postEndSession();
			
		}
	}

//	public synchronized void closeSession(){
//		getLogger().debug("Close Session Request");
//		getSession()g
//	}
	protected  void returnEntityManager(Session session){
//		session.close();
	}

//	public void transactionEnd(Transaction t){
////		Transaction t = getSession().getTransaction();
//		try{
//			t.commit();
//		}catch(Exception exception){
//			try{
//				t.rollback();
//			} catch(Exception exceptionRollBack){
//				getLogger().error( "Unable to rollback transaction", exceptionRollBack);
//				getSession().close();
//			}
//		}
//	}
	protected   Logger getLogger(){
		return logger;
	}
	
	protected void deleteByID(Serializable serializableID, Class<? extends HibernateDTO> classDTO)throws HibernateException {
		getLogger().debug("Deleting {} from {}", serializableID,classDTO.getName());
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			Query query = sessionTemp.createQuery("delete " + fromDTO(classDTO)  +  " where " + dtoAlias(classDTO,"id") + " = :id");
			query.setParameter("id",serializableID);
			query.executeUpdate();
			returnTransaction(transaction);
		}catch(HibernateException e){
				getLogger().info("Unable to delete " + classDTO.getName() + " by id:" + serializableID, e);
				rollbackTransaction(transaction);
				throw e;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
	}

	protected void deleteByField(Serializable objectValue,String stringField,Class<? extends HibernateDTO> classDTO) {
		String stringParam = convertFieldToParamater(stringField);
		String stringWhereClause = dtoAlias(classDTO,stringField) +  " = :" +  stringParam;
		Parameters paramaters = new Parameters(1);
		paramaters.setWhere(stringWhereClause);
		paramaters.addParameter(stringParam,objectValue);
		deleteByFields(paramaters, classDTO);
	}

	protected void deleteByFields(Parameters parameters,Class<? extends HibernateDTO> classDTO) {
		if(parameters == null || parameters.getWhere() == null || parameters.getWhere().length() == 0){
			throw new IllegalArgumentException("Where clause must be specified in parameters");
		}
		getLogger().debug("Deleting {} by fields", classDTO.getName());
		Session sessionTemp = null;
		String comment = "";
		String stringQuery = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			
			stringQuery = "delete " + fromDTO(classDTO)  +  " where " + parameters.getWhere().replace("?",dtoAlias(classDTO));
			// Create the Query object
			getLogger().debug("Query: {}",stringQuery); 
			Query query = sessionTemp.createQuery(stringQuery);
			// Set parameters
			for(Parameter paramater : parameters){
				comment = comment + "["+  paramater.getName() + "=:" + paramater.getValue() + "]";
				query.setParameter(paramater.getName(),paramater.getValue());
			}
			query.setComment(comment);
			getLogger().debug("Parameters: {}",comment);
			query.executeUpdate();
			returnTransaction(transaction);
		}catch(HibernateException e){
			getLogger().info( "Unable to delete " + classDTO.getName() + " by " + stringQuery + "\t" + comment, e);
			rollbackTransaction(transaction);
			throw e;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
	}

	protected void deleteByIDList(List<? extends Serializable> listOfSerializableIDs, Class<? extends HibernateDTO> classDTO)throws HibernateException {
		getLogger().debug("Deleting {} from {}", listOfSerializableIDs,classDTO.getName());
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			Query query = sessionTemp.createQuery("delete " + fromDTO(classDTO)  +  " where " + dtoAlias(classDTO,"id") + " in (:id_list)");
			query.setParameterList("id_list", listOfSerializableIDs);
			query.executeUpdate();
			returnTransaction(transaction);
		}catch(HibernateException e){
				getLogger().info("Unable to delete " + classDTO.getName() + " by id list:" + listOfSerializableIDs, e);
				rollbackTransaction(transaction);
				throw e;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
	}
	@Override
	public void delete(HibernateDTO dto){
		getLogger().debug("Deleting {}", dto.getID());
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			sessionTemp.delete(dto);
			returnTransaction(transaction);
		}catch(HibernateException e){
				getLogger().info("Unable to delete " + dto.getID(), e);
				rollbackTransaction(transaction);
				throw e;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
	}
	

	@Override
	public <T extends HibernateDTO> T refresh(T dto) {
		getLogger().info("Refreshing {} from {}", dto.getID(),dto.getClass().getName());
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
//			sessionTemp.saveOrUpdate(dto);
			sessionTemp.refresh(dto);
//			sessionTemp.update(dto);
			returnTransaction(transaction);
			
		} catch(HibernateException exception){
			getLogger().warn( "Unable to persist " + dto.getClass().getName(), exception);
			rollbackTransaction(transaction);
			throw exception;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
		getLogger().debug("Saved {} into {}", dto.getID(),dto.getClass().getName());
		return dto;
	}
	
	@Override
	public Serializable insert(HibernateDTO dto) {
		Serializable id = null;
		getLogger().info("Inserting {} into {}", dto.getID(),dto.getClass().getName());
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			id = sessionTemp.save(dto);
//			sessionTemp.update(dto);
			returnTransaction(transaction);
			
		} catch(HibernateException exception){
			getLogger().warn( "Unable to persist " + dto.getClass().getName(), exception);
			rollbackTransaction(transaction);
			throw exception;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
		getLogger().debug("Saved {} into {}", dto.getID(),dto.getClass().getName());
		return id;
	}
	

	@SuppressWarnings("unchecked")
	@Override
	public <T extends HibernateDTO> T save(T dto) {
		getLogger().info("Saving {} into {}", dto.getID(),dto.getClass().getName());
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
//			sessionTemp.saveOrUpdate(dto);
			dto = (T) sessionTemp.merge(dto);
//			sessionTemp.update(dto);
			returnTransaction(transaction);
			
		} catch(HibernateException exception){
			getLogger().warn( "Unable to persist " + dto.getClass().getName(), exception);
			rollbackTransaction(transaction);
			throw exception;
		} finally{
			if(sessionTemp != null)
				returnEntityManager(sessionTemp);
		}
		getLogger().debug("Saved {} into {}", dto.getID(),dto.getClass().getName());
		return dto;
	}
	
	
	
	@SuppressWarnings("unchecked")
	protected <T extends HibernateDTO> T getDTOByID(Serializable id,Class<T> classDTO){
		getLogger().debug("Getting {} from {}",id,classDTO.getName());
		T insightDTOReturn = null;
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			insightDTOReturn = (T) sessionTemp.get(classDTO, id);//,LockMode.NONE);
			returnTransaction(transaction);
		} catch(Exception exception){
				getLogger().info( "Unable to get " + classDTO.getName() + " by id:" + id, exception);
				rollbackTransaction(transaction);
		} finally{
				returnEntityManager(sessionTemp);
		}
		return insightDTOReturn;
	}

	@SuppressWarnings("unchecked")
	protected <T extends HibernateDTO> List<T> getDTOsByIDList(List<? extends Serializable> listOfSerializableIDs,Class<T> classDTO){
		getLogger().debug("Getting {} from {}",listOfSerializableIDs,classDTO.getName());
		List<T> listOfDTOs = new ArrayList<T>();
		Session sessionTemp = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			transaction = getTransaction();
			Query query = sessionTemp.createQuery("from " + fromDTO(classDTO)  +  " where " + dtoAlias(classDTO,"id") + " in (:id_list)");
			query.setParameterList("id_list", listOfSerializableIDs);
			listOfDTOs = query.list();
			returnTransaction(transaction);
		} catch(Exception exception){
			getLogger().info( "Unable to get " + classDTO.getName() + " by id:" + listOfSerializableIDs, exception);
			rollbackTransaction(transaction);
		} finally{
			returnEntityManager(sessionTemp);
		}
		return listOfDTOs;
	}
	
	protected <T extends HibernateDTO> List<T> getDTOsByField(Serializable objectValue,String stringField,Class<T> classDTO) {
		String stringParam = convertFieldToParamater(stringField);
		String stringWhereClause = dtoAlias(classDTO,stringField) +  " = :" +  stringParam;
		Parameters paramaters = new Parameters(1);
		paramaters.setWhere(stringWhereClause);
		paramaters.addParameter(stringParam,objectValue);
		return getDTOsByFields(paramaters,classDTO);
	}
	
	
	@Deprecated
	protected <T extends HibernateDTO> List<T> getDTOsByFields(String stringWhereClause, List<Parameter> listOfParamaters, Class<T> classDTO) {
		Parameters paramaters = new Parameters(listOfParamaters);
		paramaters.setWhere(stringWhereClause);
		return getDTOsByFields(paramaters,classDTO);
//		getLogger().debug("Get {} by feilds",classDTO.getName());
//		List<T> listOfDTODTOs = null;
//		Session sessionTemp = null;
//		String comment = "";
//		String stringQuery = null;
//		Transaction transaction = null;
//		try {
//			sessionTemp = getSession();
//			transaction = getTransaction();
//			stringQuery = "from " + fromDTO(classDTO);
//			if(stringWhereClause != null && stringWhereClause.length() > 0){
//				stringQuery = stringQuery + " where " + stringWhereClause.replace("?",dtoAlias(classDTO));
//			}
//			stringQuery = stringQuery + " order by " + dtoAlias(classDTO,"id");
//			getLogger().debug("Query: {}",stringQuery); 
//			Query query = sessionTemp.createQuery(stringQuery);
//			if(listOfParamaters != null)
//				for(Paramater paramater : listOfParamaters){
//					comment = comment + "["+  paramater.getName() + "=:" + paramater.getValue() + "]";
//					query.setParameter(paramater.getName(),paramater.getValue());
//				}
//			query.setComment(comment);
//			getLogger().debug("Parameters: {}",comment);
//			listOfDTODTOs = query.list();
//			returnTransaction(transaction);
//		} 
//		catch(Exception exception){
//				getLogger().info( "Unable to get " + classDTO.getName() + " by " + stringQuery + "\t" + comment, exception);
//				rollbackTransaction(transaction);
//		} finally{
//			returnEntityManager(sessionTemp);
//		}
//		return listOfDTODTOs;

	}
	
	protected <T extends HibernateDTO> List<T> getDTOs(Class<T> classDTO) {
		return getDTOsByFields(null,classDTO);
	}
	
	@SuppressWarnings("unchecked")
	protected <T extends HibernateDTO> List<T> getDTOsByFields(Parameters parameters, Class<T> classDTO) {
		getLogger().debug("Get {} by fields",classDTO.getName());
		List<T> listOfDTODTOs = null;
		Session sessionTemp = null;
//		String comment = "";
//		String stringQuery = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			Query query = createQuery(parameters,classDTO,sessionTemp);
			transaction = getTransaction();
//			// Build Select/From clause
//			if(parameters != null && parameters.getSelectFrom() != null && parameters.getSelectFrom().length() > 0) {
//				stringQuery = parameters.getSelectFrom();
//			} else {
//				stringQuery = "from " + fromDTO(classDTO);
//			}
//			// Build Where clause
//			if(parameters != null && parameters.getWhere() != null && parameters.getWhere().length() > 0){
//				stringQuery = stringQuery + " where " + parameters.getWhere().replace("?",dtoAlias(classDTO));
//			}
//			// Build Order By clause
//			if(parameters != null && parameters.getOrderBy() != null && parameters.getOrderBy().length() > 0){
//				stringQuery = stringQuery + " order by " + parameters.getOrderBy().replace("?",dtoAlias(classDTO));
//			} else {
//				stringQuery = stringQuery + " order by " + dtoAlias(classDTO,"id");
//			}
//			
//			// Create the Query object
//			getLogger().debug("Query: {}",stringQuery); 
//			Query query = sessionTemp.createQuery(stringQuery);
////			query.setLockMode(arg0, arg1)
//			// Set parameters
//			if(parameters != null) {
//				for(Parameter paramater : parameters){
//					comment = comment + "["+  paramater.getName() + "=:" + paramater.getValue() + "]";
//					query.setParameter(paramater.getName(),paramater.getValue());
//				}
//			}
//			query.setComment(comment);
//			getLogger().debug("Parameters: {}",comment);
			listOfDTODTOs = query.list();
			returnTransaction(transaction);
		} catch(Exception exception) {
			getLogger().info( "Unable to get " + classDTO.getName(), exception);
			rollbackTransaction(transaction);
		} finally {
			returnEntityManager(sessionTemp);
		}
		return listOfDTODTOs;
	}
	
	
	@SuppressWarnings("unchecked")
	protected <T extends HibernateDTO> T getDTOByFields(Parameters parameters, Class<T> classDTO) {
		getLogger().debug("Get {} by feilds",classDTO.getName());
		T listOfDTODTOs = null;
		Session sessionTemp = null;
//		String stringQuery = null;
		Transaction transaction = null;
		try {
			sessionTemp = getSession();
			Query query = createQuery(parameters,classDTO,sessionTemp);
			transaction = getTransaction();
//			// Build Select/From clause
//			if(parameters != null && parameters.getSelectFrom() != null && parameters.getSelectFrom().length() > 0) {
//				stringQuery = parameters.getSelectFrom();
//			} else {
//				stringQuery = "from " + fromDTO(classDTO);
//			}
//			// Build Where clause
//			if(parameters != null && parameters.getWhere() != null && parameters.getWhere().length() > 0){
//				stringQuery = stringQuery + " where " + parameters.getWhere().replace("?",dtoAlias(classDTO));
//			}
//			// Build Order By clause
//			if(parameters != null && parameters.getOrderBy() != null && parameters.getOrderBy().length() > 0){
//				stringQuery = stringQuery + " order by " + parameters.getOrderBy().replace("?",dtoAlias(classDTO));
//			} else {
//				stringQuery = stringQuery + " order by " + dtoAlias(classDTO,"id");
//			}
//			
//			// Create the Query object
//			getLogger().debug("Query: {}",stringQuery); 
//			Query query = sessionTemp.createQuery(stringQuery);
//			// Set parameters
//			if(parameters != null) {
//				for(Parameter paramater : parameters){
//					comment = comment + "["+  paramater.getName() + "=:" + paramater.getValue() + "]";
//					query.setParameter(paramater.getName(),paramater.getValue());
//				}
//			}
//			query.setComment(comment);
//			getLogger().debug("Parameters: {}",comment);
			listOfDTODTOs = (T) query.uniqueResult();
			returnTransaction(transaction);
		} catch(Exception exception) {
				getLogger().info( "Unable to get " + classDTO.getName(), exception);
				rollbackTransaction(transaction);
		} finally {
			returnEntityManager(sessionTemp);
		}
		return listOfDTODTOs;
	}
	
//	protected <T extends HibernateDTO> List<T> getDTOByField(double doubleValue,String stringField,Class<T> classDTO) {
//		String stringWhereClause = dtoAlias(classDTO) + "." + stringField + " = :" + stringField;
//		List<Paramater> listOfParamaters = new ArrayList<Paramater>();
//		listOfParamaters.add(new Paramater(new Double(doubleValue),stringField));
//		return getDTOsByFields(stringWhereClause,listOfParamaters,classDTO);
//
//	}
	
	private Query createQuery(Parameters parameters, Class<? extends HibernateDTO> classDTO, Session session){
		if(classDTO == null || session == null )
			throw new InvalidParameterException();
		String comment = "";
		String stringQuery = null;
		// Build Select/From clause
		if( parameters != null && parameters.getSelectFrom() != null && parameters.getSelectFrom().length() > 0) {
			stringQuery = parameters.getSelectFrom();
		} else {
			stringQuery = "from " + fromDTO(classDTO);
		}
		// Build Where clause
		if( parameters != null && parameters.getWhere() != null && parameters.getWhere().length() > 0){
			stringQuery = stringQuery + "\n\t where " + parameters.getWhere().replace("?",dtoAlias(classDTO));
		}
		// Build Order By clause
		if( parameters != null && parameters.getOrderBy() != null && parameters.getOrderBy().length() > 0){
			stringQuery = stringQuery + "\n\t order by " + parameters.getOrderBy().replace("?",dtoAlias(classDTO));
		} else {
			stringQuery = stringQuery + "\n\t order by " + dtoAlias(classDTO,"id");
		}
		
		// Create the Query object
		getLogger().debug("Query: {}",stringQuery); 
		Query query = session.createQuery(stringQuery);
		// Set parameters
		if(parameters != null && parameters.getOffset() != null){
			query.setFirstResult(parameters.getOffset());
		}
		if(parameters != null && parameters.getCount() != null){
			query.setMaxResults(parameters.getCount());
		}
		if( parameters != null){
			for(Parameter paramater : parameters){
				comment = comment + "["+  paramater.getName() + "=:" + paramater.getValue() + "]";
				query.setParameter(paramater.getName(),paramater.getValue());
			}
		}
		query.setComment(comment);
		getLogger().debug("Parameters: {}",comment);
		if( parameters != null && parameters.getLockMode() != null && (parameters.getSelectFrom() == null  || parameters.getSelectFrom().length() == 0)){
			query.setLockMode(dtoAlias(classDTO), parameters.getLockMode());
		}
		return query;
	}
}
